#include <GL/glew.h>		//Handles extension loading for Windows
#include <iostream>
#include "Shader.h"
#include "ShaderProgram.h"

ShaderProgram::ShaderProgram(Shader* vertexShader, Shader* fragmentShader):vs(vertexShader),fs(fragmentShader)
{
	// Create the program object
	progID = glCreateProgram();
	if(!progID)
	{
		std::cout<<"Failed to create program object\n";		
	}
	//Bind vertex/fragment shaders to this shader program
	glAttachShader(progID, vs->getID());
	glAttachShader(progID, fs->getID());	

}


void ShaderProgram::Use()
{
	glUseProgram(progID);//Use the shaderprogram for all draw calls following this call
}

void ShaderProgram::Link()
{	
	// Link the program
	glLinkProgram(progID);
	// Check the link status
	int linked;
	glGetProgramiv(progID, GL_LINK_STATUS, &linked);
	if(!linked)
	{
		GLint infoLen = 0;
		glGetProgramiv(progID, GL_INFO_LOG_LENGTH, &infoLen);
		if(infoLen > 1)
		{
			char* infoLog = new char[infoLen];
			glGetProgramInfoLog(progID, infoLen, NULL, infoLog);
			std::cout<<"Error linking program:\n"<<infoLog<<"\n";
			delete infoLog;
		}
		glDeleteProgram(progID);		
	}	

}

int ShaderProgram::getUniformLocation(const std::string& uniform)
{
	return glGetUniformLocation(progID, uniform.c_str());	//Get the location in the Shaderprogram which maps to @uniform in the shader source code
}

void ShaderProgram::addAttribute(const std::string &attribute)
{//add and map attributes to integers starting from 0..n
	glBindAttribLocation(progID, attributes.size(), attribute.c_str());
	attributes.push_back(attribute);
}

unsigned int ShaderProgram::getID()
{//Returns the OpenGL id for this shader program
	return progID;	
}


ShaderProgram::~ShaderProgram()
{
	glDeleteProgram(progID);
}